﻿// learn-game.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//


// Plan:
// Static Data:
// 1. Map(Block, Box, initPosition) ok
// States:
// -  cmd ok
// -  Position 
// -  Box Position
// Contrains:
// - Block 
// - Box 
//


#include <iostream>
using namespace std;


// Map 
const int nrow = 5;
const int ncol = 8;

const char map[10][10] = 
{
	"********",
	"*      *",
	"*      *",
	"*      *",
	"********"
};

const int nbox = 2;
const int boxPosition[nbox][2] = 
{
	{2, 2},
	{2, 3}
};
const int boxDestination[nbox][2] = 
{
	{1, 2},
	{1, 3}
};
const int initPosition[2] = { 1, 5 };


// State
enum  Direction
{
	UP, RIGHT, DOWN, LEFT, UNKNOWN
};

Direction cmd;
int currentPosition[2];
int currentBoxPosition[nbox][2];
char currentMap[10][10];

void init();
void getInput();
Direction convertCharToDirection(char c);

void updateGame();
void checkWin();
void draw();


int main()
{
    std::cout << "Hello World!\n";
	init();
	updateGame();
	draw();
	while (true)
	{
		getInput();
		updateGame();
		draw();
	}
}

void init()
{
	currentPosition[0] = initPosition[0];
	currentPosition[1] = initPosition[1];

	int i;
	for (i = 0; i < nbox; ++i)
	{
		currentBoxPosition[i][0] = boxPosition[i][0];
		currentBoxPosition[i][1] = boxPosition[i][1];
	}

}

void getInput()
{
	cout << "Press wsad to move:    ";
	char c;
	cin >> c;
	cmd = convertCharToDirection(c);
}

Direction convertCharToDirection(char c)
{
	Direction dir;
	switch (c)
	{
	case	'w': dir = UP; break;
	case 'd': dir = RIGHT; break;
	case 's': dir = DOWN; break;
	case 'a': dir = LEFT; break;
	default:
		dir = UNKNOWN;
	}
	return dir;
}

void updateGame()
{

	if (cmd == UP) {
		int newPosition[2];
		newPosition[0] = currentPosition[0] - 1;
		newPosition[1] = currentPosition[1];

		bool canWalk = true;
		// Validate
		if (map[newPosition[0]][newPosition[1]] == '*')
			canWalk = false;
		if (currentMap[newPosition[0]][newPosition[1]] == 'o'
			&& (currentMap[newPosition[0] - 1][newPosition[1]] == 'o' 
				|| currentMap[newPosition[0] - 1][newPosition[1]] == '*'))
			canWalk = false;

		if (canWalk) {
			// Push
			if (currentMap[newPosition[0]][newPosition[1]] == 'o') {
				int i;
				for (i = 0; i <= nbox; ++i) {
					if (currentBoxPosition[i][0] == newPosition[0]
						&& currentBoxPosition[i][1] == newPosition[1]) {
						currentBoxPosition[i][0] -= 1;
					}
				}
			}
			currentPosition[0] = newPosition[0];
			currentPosition[1] = newPosition[1];
		}
	}
	else if (cmd == DOWN) {
		int newPosition[2];
		newPosition[0] = currentPosition[0] + 1;
		newPosition[1] = currentPosition[1];

		bool canWalk = true;
		// Validate
		if (map[newPosition[0]][newPosition[1]] == '*')
			canWalk = false;
		if (currentMap[newPosition[0]][newPosition[1]] == 'o'
			&& (currentMap[newPosition[0] + 1][newPosition[1]] == 'o'
				|| currentMap[newPosition[0] + 1][newPosition[1]] == '*'))
			canWalk = false;

		if (canWalk) {
			// Push
			if (currentMap[newPosition[0]][newPosition[1]] == 'o') {
				int i;
				for (i = 0; i <= nbox; ++i) {
					if (currentBoxPosition[i][0] == newPosition[0]
						&& currentBoxPosition[i][1] == newPosition[1]) {
						currentBoxPosition[i][0] += 1;
					}
				}
			}
			currentPosition[0] = newPosition[0];
			currentPosition[1] = newPosition[1];
		}
	}
	else if (cmd == LEFT) {
		int newPosition[2];
		newPosition[0] = currentPosition[0];
		newPosition[1] = currentPosition[1] - 1;

		bool canWalk = true;
		// Validate
		if (map[newPosition[0]][newPosition[1]] == '*')
			canWalk = false;
		if (currentMap[newPosition[0]][newPosition[1]] == 'o'
			&& (currentMap[newPosition[0] ][newPosition[1] - 1] == 'o'
				|| currentMap[newPosition[0]][newPosition[1] - 1] == '*'))
			canWalk = false;

		if (canWalk) {
			// Push
			if (currentMap[newPosition[0]][newPosition[1]] == 'o') {
				int i;
				for (i = 0; i <= nbox; ++i) {
					if (currentBoxPosition[i][0] == newPosition[0]
						&& currentBoxPosition[i][1] == newPosition[1]) {
						currentBoxPosition[i][1] -= 1;
					}
				}
			}
			currentPosition[0] = newPosition[0];
			currentPosition[1] = newPosition[1];
		}
	}
	else if (cmd == RIGHT) {
		int newPosition[2];
		newPosition[0] = currentPosition[0] ;
		newPosition[1] = currentPosition[1] + 1;

		bool canWalk = true;
		// Validate
		if (map[newPosition[0]][newPosition[1]] == '*')
			canWalk = false;
		if (currentMap[newPosition[0]][newPosition[1]] == 'o'
			&& (currentMap[newPosition[0]][newPosition[1] + 1] == 'o'
				|| currentMap[newPosition[0]][newPosition[1] + 1] == '*'))
			canWalk = false;

		if (canWalk) {
			// Push
			if (currentMap[newPosition[0]][newPosition[1]] == 'o') {
				int i;
				for (i = 0; i <= nbox; ++i) {
					if (currentBoxPosition[i][0] == newPosition[0]
						&& currentBoxPosition[i][1] == newPosition[1]) {
						currentBoxPosition[i][1] += 1;
					}
				}
			}
			currentPosition[0] = newPosition[0];
			currentPosition[1] = newPosition[1];
		}
	}
	else {

	}

	// Update Map
	int i, j;
	for (i = 0; i < nrow; ++i)
	{
		for (j = 0; j < ncol; ++j)
		{
			currentMap[i][j] = map[i][j];
		}
		cout << endl;
	}
	for (i = 0; i < nbox; ++i)
	{
		currentMap[boxDestination[i][0]][boxDestination[i][1]] = '.';
	}

	currentMap[currentPosition[0]][currentPosition[1]] = 'p';
	for (i = 0; i < nbox; ++i)
	{
		currentMap[currentBoxPosition[i][0]][currentBoxPosition[i][1]] = 'o';
	}

	checkWin();

}
void checkWin() {
	bool isWin = true;

	bool isPlaced;
	int i, j;
	for (i = 0; i < nbox; ++i) {
		isPlaced = false;
		for (j = 0; j < nbox; ++j) {
			if (currentBoxPosition[i][0] == boxDestination[j][0]
				&& currentBoxPosition[i][1] == boxDestination[j][1]) {
				isPlaced = true;
				break;
			}
		}
		if (!isPlaced) {
			isWin = false;
			break;
		}
	}

	if (isWin) {
		draw();
		cout << "You Won!!!";
		while (true)
		{

		}
	}
}

void draw()
{
	// Draw Map
	int i, j;
	for (i = 0; i < nrow; ++i)
	{
		for (j = 0; j < ncol; ++j)
		{
			cout << currentMap[i][j];
		}
		cout << endl;
	}

}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
